package org.study.mybatis.result;

import org.study.mybatis.binding.MapperMethod;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 默认的结果集映射处理器的实现，这里就是处理返回参数和对象的数据绑定
 */
public class DefaultResultSetHandler implements ResultSetHandler {
    @Override
    public <T> T handle(PreparedStatement pstmt, MapperMethod mapperMethod) throws Exception {
        Object resultObj = DefaultObject.createObjectByType(mapperMethod.getType());
        //获取数据库的结果
        ResultSet rs = pstmt.getResultSet();
        if (rs.next()) {
            int i = 0;
            //开始给返回对象的属性赋值
            for (Field field : resultObj.getClass().getDeclaredFields()) {
                //对象属性赋值
                setValue(resultObj, field, rs, i);
            }
        }
        return (T) resultObj;
    }

    /**
     * @param resultObj 需要赋值的对象
     * @param field     属性
     * @param rs        值,就是从mysql查询出来的列
     * @param i         本来设计的是第几个，但是后来没用上
     * @throws NoSuchMethodException
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private void setValue(Object resultObj, Field field, ResultSet rs, int i) throws NoSuchMethodException, SQLException, InvocationTargetException, IllegalAccessException {
        //构造对象的方法
        Method setMethod = resultObj.getClass().getMethod("set" + upperCapital(field.getName()), field.getType());
        //通过反射set方法来给对象属性赋值
        setMethod.invoke(resultObj, getResult(field, rs));
    }

    //属性首字母大写,配合set字符串，变成setXxx
    private String upperCapital(String name) {
        String first = name.substring(0, 1);
        String tail = name.substring(1);
        return first.toUpperCase() + tail;
    }

    //属性和返回结果的映射对照
    private Object getResult(Field field, ResultSet rs) throws SQLException {
        //获取属性类型
        Class<?> type = field.getType();
        if (Integer.class == type) {
            //通过属性类型来获取sql返回的值类型
            return rs.getInt(field.getName());
        }
        if (String.class == type) {
            return rs.getString(field.getName());
        }
        if (Long.class == type) {
            return rs.getLong(field.getName());
        }
        return rs.getString(field.getName());
    }

}
